import { ApiMsgEnum, EntityTypeEnum, IClientInput, IMsgClientSync, InputTypeEnum, IState, toFixed } from "../Common";
import { Connection } from "../Core/Connections";
import { Player } from "./Player";
import { PlayerManager } from "./PlayerManager";
import { RoomManager } from "./RoomManager";

export class Room {
    id:number;
    players:Set<Player> = new Set();

    lastTime:number;
    pendingInput:IClientInput[] = [];
    lastPlayerFrameIdMap:Map<number,number> = new Map();

    constructor(rid:number){
        this.id = rid;
    }

    join(uid:number){
        const player = PlayerManager.Instance.idMapPlayer.get(uid);
        if(player){
            this.players.add(player);
            player.rid = this.id;
        }
    }

    leave(uid:number){
        const player = PlayerManager.Instance.idMapPlayer.get(uid);
        if(player){
            player.rid = undefined;
            this.players.delete(player);
            if(!this.players.size){
                RoomManager.Instance.closeRoom(this.id);
            }
        } 
    }

    close(){
        for(const player of this.players){
            player.rid = undefined;
        }
        this.players.clear();
    }

    sync(){
        for(const player of this.players){
            player.connection.sendMsg(ApiMsgEnum.MsgRoom,{
                room:RoomManager.Instance.getRoomView(this)
            }) 
        }
    }

    start(){
        const state:IState = {
            actors: [...this.players].map((player,index)=>({
                id: player.id,
                nickname: player.nickname,
                hp: 100,
                type: EntityTypeEnum.Actor1,
                weaponType:EntityTypeEnum.Weapon1,
                bulletType: EntityTypeEnum.Bullet2,
                position: { x: -300 + index * 200,
                            y: 0 },
                direction: { x: 1, y: 0 },
                  
            })),
            bullets: [],
            nextBulletId: 1,
            seed: 1,
        }

        for(const player of this.players){
            player.connection.sendMsg(ApiMsgEnum.MsgGameStart,{
                state,
            }) 

            player.connection.listenMsg(ApiMsgEnum.MsgClientSync,this.getClientMsg,this);
        }

        const time1 = setInterval(()=>{
            this.sendServerMsg();
        }, 100);

        const time2 = setInterval(()=>{
            this.timePast();
        }, 16);
    }

    getClientMsg(connection:Connection,{input,frameId}: IMsgClientSync) {
        this.pendingInput.push(input);
        this.lastPlayerFrameIdMap.set(connection.playerId,frameId);
    }

    sendServerMsg(){
        const inputs = this.pendingInput;
        this.pendingInput = [];
        for(const player of this.players){
            player.connection.sendMsg(ApiMsgEnum.MsgServerSync,{
                inputs,
                lastFrameId: this.lastPlayerFrameIdMap.get(player.id) ?? 0,
            }) 
        }
    }

    timePast(){
        const now = process.uptime();
        const dt = now - (this.lastTime ?? 0);
        this.lastTime = now;

        this.pendingInput.push({
            type:InputTypeEnum.TimePast,
            dt:toFixed(dt),
        })
    }
}